package ls

import (
	"fmt"
	"strings"

	"gitee.com/eeppee_admin/go-tuiftp/reuse"
	"github.com/charmbracelet/bubbles/key"
	"github.com/charmbracelet/bubbles/table"
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
	"github.com/jlaffaye/ftp"
)

var (
	baseStyle = lipgloss.NewStyle().
		BorderStyle(lipgloss.NormalBorder()).
		BorderForeground(lipgloss.Color("240"))
)

type keyMap struct {
	Up    key.Binding
	Down  key.Binding
	Enter key.Binding
	Back  key.Binding
	Quit  key.Binding
}

func (k keyMap) ShortHelp() []key.Binding {
	return []key.Binding{k.Up, k.Down, k.Enter, k.Back, k.Quit}
}

func (k keyMap) FullHelp() [][]key.Binding {
	return [][]key.Binding{
		{k.Up, k.Down},
		{k.Enter, k.Back},
		{k.Quit},
	}
}

var keys = keyMap{
	Up: key.NewBinding(
		key.WithKeys("up", "k"),
		key.WithHelp("↑/k", "上移"),
	),
	Down: key.NewBinding(
		key.WithKeys("down", "j"),
		key.WithHelp("↓/j", "下移"),
	),
	Enter: key.NewBinding(
		key.WithKeys("enter"),
		key.WithHelp("enter", "进入目录"),
	),
	Back: key.NewBinding(
		key.WithKeys("backspace"),
		key.WithHelp("backspace", "返回上级"),
	),
	Quit: key.NewBinding(
		key.WithKeys("q", "ctrl+c"),
		key.WithHelp("q/ctrl+c", "退出"),
	),
}

type entry struct {
	name      string
	size      string
	modTime   string
	entryType string
	ftpEntry  *ftp.Entry
}

type model struct {
	table    table.Model
	client   *reuse.FtpClient
	site     *reuse.SiteConfig
	currPath string
	entries  []entry
	loading  bool
	err      error
}

func newModel(client *reuse.FtpClient, site *reuse.SiteConfig, initialPath string) model {
	columns := []table.Column{
		{Title: "名称", Width: 30},
		{Title: "大小", Width: 12},
		{Title: "修改时间", Width: 20},
		{Title: "类型", Width: 8},
	}

	t := table.New(
		table.WithColumns(columns),
		table.WithFocused(true),
		table.WithHeight(15),
	)

	s := table.DefaultStyles()
	s.Header = s.Header.
		BorderStyle(lipgloss.NormalBorder()).
		BorderForeground(lipgloss.Color("240")).
		Foreground(lipgloss.Color("240"))
	s.Selected = s.Selected.
		Foreground(lipgloss.Color("229")).
		Background(lipgloss.Color("57")).
		Bold(false)
	t.SetStyles(s)

	return model{
		table:    t,
		client:   client,
		site:     site,
		currPath: initialPath,
		loading:  true,
	}
}

func (m model) Init() tea.Cmd {
	return m.loadEntries
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.KeyMsg:
		switch {
		case key.Matches(msg, keys.Quit):
			return m, tea.Quit
		case key.Matches(msg, keys.Back):
			if m.currPath != "/" {
				// 返回上级目录
				lastSlash := strings.LastIndex(m.currPath[:len(m.currPath)-1], "/")
				if lastSlash == -1 {
					m.currPath = "/"
				} else {
					m.currPath = m.currPath[:lastSlash+1]
				}
				m.loading = true
				return m, m.loadEntries
			}
		case key.Matches(msg, keys.Enter):
			// 进入选中的目录
			selectedRow := m.table.SelectedRow()
			if len(selectedRow) == 0 {
				return m, nil
			}
			entryName := selectedRow[0]

			for _, e := range m.entries {
				if e.name == entryName && e.entryType == "文件夹" {
					newPath := m.currPath + e.name + "/"
					m.currPath = newPath
					m.loading = true
					return m, m.loadEntries
				}
			}
		}

	case []entry:
		// 更新列表数据
		m.entries = msg
		rows := make([]table.Row, len(msg))
		for i, e := range msg {
			rows[i] = table.Row{e.name, e.size, e.modTime, e.entryType}
		}
		m.table.SetRows(rows)
		m.loading = false
		return m, nil

	case error:
		m.err = msg
		m.loading = false
		return m, nil
	}

	// 处理表格的更新
	var cmd tea.Cmd
	m.table, cmd = m.table.Update(msg)
	return m, cmd
}

func (m model) View() string {
	if m.err != nil {
		return fmt.Sprintf("错误: %v\n按任意键退出...", m.err)
	}

	if m.loading {
		return fmt.Sprintf("加载中 %s:%s...\n", m.site.Name, m.currPath)
	}

	header := fmt.Sprintf("站点: %s | 当前路径: %s\n", m.site.Name, m.currPath)
	// help := keys.ShortHelp([]key.Binding{keys.Enter, keys.Back, keys.Quit})
	return baseStyle.Render(lipgloss.JoinVertical(
		lipgloss.Left,
		header,
		m.table.View(),
		// help,
	))
}

// 加载目录条目
func (m *model) loadEntries() tea.Msg {
	entries, err := m.client.Conn.List(m.currPath)
	if err != nil {
		return fmt.Errorf("列出目录失败: %v", err)
	}

	var result []entry
	for _, e := range entries {
		// 跳过.和..
		if e.Name == "." || e.Name == ".." {
			continue
		}

		entryType := "文件"
		if e.Type == ftp.EntryTypeFolder {
			entryType = "文件夹"
		}

		result = append(result, entry{
			name:      e.Name,
			size:      reuse.HumanReadableSize(e.Size),
			modTime:   e.Time.Format("2006-01-02 15:04"),
			entryType: entryType,
			ftpEntry:  e,
		})
	}
	return result
}
